package com.dingxin.ship_together_api.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dingxin.ship_together_api.common.utils.PageUtils;
import com.dingxin.ship_together_api.common.utils.SaUtils;
import com.dingxin.ship_together_api.config.exception.CustomException;
import com.dingxin.ship_together_api.config.rabbitmq.DelayMessageSender;
import com.dingxin.ship_together_api.config.rabbitmq.DelayTypeEnum;
import com.dingxin.ship_together_api.entity.OrderInfo;
import com.dingxin.ship_together_api.entity.OrderInfoDetail;
import com.dingxin.ship_together_api.entity.RouteSeat;
import com.dingxin.ship_together_api.entity.RouteSku;
import com.dingxin.ship_together_api.entity.enums.ExceptionEnum;
import com.dingxin.ship_together_api.entity.enums.OrderStatusEnum;
import com.dingxin.ship_together_api.entity.enums.RouteTypeEnum;
import com.dingxin.ship_together_api.entity.vo.PageQueryVo;
import com.dingxin.ship_together_api.entity.vo.order.OrderAddVo;
import com.dingxin.ship_together_api.mapper.OrderInfoMapper;
import com.dingxin.ship_together_api.mapper.OrderSnapshotMapper;
import com.dingxin.ship_together_api.mapper.RouteSeatMapper;
import com.dingxin.ship_together_api.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
* Author: ctj
* Date: 2022-09-14
* Time: 11:21
*/

@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService{
    @Autowired
    private OrderInfoMapper orderInfoMapper;
    @Autowired 
    private OrderContactsService orderContactsService;
    @Autowired
    private RouteSpuService routeSpuService;
    @Autowired
    private RouteSkuService routeSkuService;
    @Autowired
    private OrderSnapshotMapper orderSnapshotMapper;
    @Autowired
    private RouteSeatMapper routeSeatMapper;
    @Autowired
    private RouteSeatService routeSeatService;
    @Autowired
    private OrderInfoDetailService orderInfoDetailService;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private SaUtils saUtils;
    @Autowired
    private DelayMessageSender sender;
    @Autowired
    private ThreadPoolExecutor threadPoolExecutor;


    @Override public PageUtils selectPage(PageQueryVo pageQueryVo) {
        // 设置分页大小
        Page<OrderInfo> page = new Page<>(pageQueryVo.getCurrPage(),pageQueryVo.getPageSize());
        // 构造分页查询条件
        QueryWrapper<OrderInfo> queryWrapper = new QueryWrapper<>();
        if (pageQueryVo.getOrderStatus()!=null && !StringUtils.isBlank(pageQueryVo.getOrderStatus().toString())) {
            queryWrapper.eq(OrderInfo.COL_STATUS,pageQueryVo.getOrderStatus());
        }
        // 分页查询
        Page<OrderInfo> resPage = orderInfoMapper.selectPage(page, saUtils.generateQueryWrapper(queryWrapper,pageQueryVo));
        PageUtils pageUtils = new PageUtils(resPage);
        // 结果封装
        return pageUtils;
    }



    @Transactional(rollbackFor = Exception.class)
    @Override
    public OrderInfo save(OrderAddVo orderAddVo) {
        // 校验当前时间是否超出下单截止时间
        boolean beyond= routeSpuService.checkBeyondDeadline(orderAddVo.getSkuId());
        if (beyond) {
            throw new CustomException(ExceptionEnum.BEYOND_DEADLINE);
        }
        // 获取航线spu类型
        RouteTypeEnum routeType = routeSkuService.getRouteType(orderAddVo.getSkuId());
        // 拼船情况下，检测当前座位是否已被预定
        if (RouteTypeEnum.SPELL_SEATS.getCode().equals(routeType.getCode())) {
            // 如果传入参数为空，抛出异常
            if (CollectionUtils.isEmpty(orderAddVo.getSeatsIdList())) {
                throw new CustomException(ExceptionEnum.SEAT_NOT_FOUND);
            }
            // 如果座位已被预定，方法内部抛出异常
            routeSeatService.checkSeatUsed(orderAddVo.getSkuId(),orderAddVo.getSeatsIdList());
        }
        // 保存订单信息
        OrderInfo orderInfo = saveOrderInfo(orderAddVo, routeType);
        orderInfo.setPrepayWithRequestPaymentResponse(wxPayService.genPrePayInfo(orderInfo));
        return orderInfo;
    }

    /**
     * 保存订单信息
     * @param orderAddVo
     * @param routeType
     */
    private OrderInfo saveOrderInfo(OrderAddVo orderAddVo, RouteTypeEnum routeType) {
        OrderInfo orderInfo = new OrderInfo();
        // 拼船的保存订单逻辑
        if (routeType.getCode().equals(RouteTypeEnum.SPELL_SEATS.getCode())) {
            // 1. 扣减sku库存
            List<RouteSku> updateList;
            synchronized (this){
                updateList = routeSkuService.list(new QueryWrapper<RouteSku>().in(RouteSku.COL_SEAT_ID,orderAddVo.getSeatsIdList()).eq(RouteSku.COL_DELETED, false));
                updateList.forEach(routeSku -> {
                    if ((routeSku.getStock()-1)<0) {
                        throw new CustomException(ExceptionEnum.OUT_OF_STOCK);
                    }
                    routeSku.setStock(routeSku.getStock()-1);
                });
                routeSkuService.updateBatchById(updateList);
            }
            // 2. 修改座位状态
            List<RouteSeat> routeSeats = routeSeatService.listByIds(orderAddVo.getSeatsIdList());
            routeSeats.forEach(seat->seat.setUsed(true));
            routeSeatService.updateBatchById(routeSeats);
            // 3. 保存订单信息
            //   3.1 校验前端传入的amount是否正确
            if (!orderAddVo.getAmount().equals(routeSeats.stream().mapToLong(RouteSeat::getAmount).sum())) {
                throw new CustomException(ExceptionEnum.AMOUNT_NOT_CORRECT);
            }
            //   3.2 保存订单信息
            orderInfo.setAmount(orderAddVo.getAmount());
            orderInfo.setRouteType(routeType.getCode());
            orderInfo.setPeopleCount(orderAddVo.getSeatsIdList().size());
            orderInfo.setStatus(OrderStatusEnum.WAIT_PAY.getCode());
            orderInfoMapper.insert(orderInfo);
            CompletableFuture.runAsync(()->{
                //   3.3 保存订单详情
                ArrayList<OrderInfoDetail> orderInfoDetailsInsertList = new ArrayList<>();
                updateList.forEach(routeSku -> {
                    OrderInfoDetail orderInfoDetail = new OrderInfoDetail();
                    orderInfoDetail.setOrderId(orderInfo.getId());
                    orderInfoDetail.setSkuId(routeSku.getId());
                    orderInfoDetail.setPrice(routeSku.getAmount());
                    orderInfoDetail.setNum(1);
                    orderInfoDetailsInsertList.add(orderInfoDetail);
                });
                orderInfoDetailService.saveBatch(orderInfoDetailsInsertList);
                // 4.保存订单联系人信息
                orderAddVo.getContactsList().forEach(contact->contact.setOrderId(orderInfo.getId()));
                orderContactsService.saveBatch(orderAddVo.getContactsList());
                // 5.发送消息到延时队列
                sender.sendMsg(orderInfo.getId().toString(), DelayTypeEnum.DELAY_30m);
            },threadPoolExecutor);

        }
        // 包船的保存订单逻辑
        if (routeType.getCode().equals(RouteTypeEnum.All_SEATS.getCode())) {
            // 1. 扣减sku库存
            RouteSku sku;
            List<RouteSku> allSku;
            synchronized (this){
                // 1.1 扣减sku库存
                sku = routeSkuService.getOne(new QueryWrapper<RouteSku>().eq(RouteSku.COL_ID, orderAddVo.getSkuId()).eq(RouteSku.COL_DELETED, false));
                allSku = routeSkuService.list(new QueryWrapper<RouteSku>().in(RouteSku.COL_ROUTE_SPU_ID,sku.getRouteSpuId()).eq(RouteSku.COL_DELETED, false));
                allSku.forEach(routeSku -> {
                    if ((routeSku.getStock()-1)<0) {
                        throw new CustomException(ExceptionEnum.OUT_OF_STOCK);
                    }
                    routeSku.setStock(routeSku.getStock()-1);
                });
                routeSkuService.updateBatchById(allSku);
            }
            // 2.校验前端传入的amount是否正确
            if (!orderAddVo.getAmount().equals(sku.getAmount())) {
                throw new CustomException(ExceptionEnum.AMOUNT_NOT_CORRECT);
            }
            //   3.1 保存订单信息
            orderInfo.setAmount(orderAddVo.getAmount());
            orderInfo.setRouteType(routeType.getCode());
            orderInfo.setStatus(OrderStatusEnum.WAIT_PAY.getCode());
            orderInfoMapper.insert(orderInfo);
            CompletableFuture.runAsync(() -> {
                //   3.2 保存订单详情
                OrderInfoDetail orderInfoDetail = new OrderInfoDetail();
                orderInfoDetail.setOrderId(orderInfo.getId());
                orderInfoDetail.setSkuId(sku.getId());
                orderInfoDetail.setPrice(sku.getAmount());
                orderInfoDetail.setNum(1);
                orderInfoDetailService.save(orderInfoDetail);
                // 4.保存订单联系人信息
                orderAddVo.getContactsList().forEach(contact -> contact.setOrderId(orderInfo.getId()));
                orderContactsService.saveBatch(orderAddVo.getContactsList());
                // 5.发送消息到延时队列
                sender.sendMsg(orderInfo.getId().toString(), DelayTypeEnum.DELAY_30m);
            }, threadPoolExecutor);
        }

        return orderInfo;
    }


    /**
     * 取消订单
     * @param orderId
     */
    @Transactional(rollbackFor = Exception.class)
    @Override public void cancelOrder(Long orderId) {
        // 1.查询订单信息,不存在说明已支付，方法结束
        QueryWrapper<OrderInfo> wrapper = new QueryWrapper<>();
        wrapper.eq(OrderInfo.COL_ID, orderId).eq(OrderInfo.COL_STATUS, OrderStatusEnum.WAIT_PAY.getCode());
        OrderInfo orderInfo = orderInfoMapper.selectOne(wrapper);
        if (orderInfo == null) {return;}
        // 2.修改订单状态为超时未支付
        orderInfo.setStatus(OrderStatusEnum.PAY_TIME_OUT.getCode());
        orderInfoMapper.updateById(orderInfo);
        // 3.恢复航线sku库存
        if (orderInfo.getRouteType().equals(RouteTypeEnum.SPELL_SEATS.getCode())) {
            //恢复拼船sku库存
            List<OrderInfoDetail> orderInfoDetailList = orderInfoDetailService.list(new QueryWrapper<OrderInfoDetail>().eq(OrderInfoDetail.COL_ORDER_ID, orderId).eq(OrderInfoDetail.COL_DELETED, false));
            List<Long> skuIdList = orderInfoDetailList.stream().map(OrderInfoDetail::getSkuId).collect(Collectors.toList());
            List<RouteSku> skuList = routeSkuService.list(new QueryWrapper<RouteSku>().in(RouteSku.COL_ID, skuIdList));
            skuList.forEach(routeSku -> routeSku.setStock(routeSku.getStock()+1));
            routeSkuService.updateBatchById(skuList);
            //恢复座位使用状态
            List<RouteSeat> seatList = routeSeatService.list(new QueryWrapper<RouteSeat>().in(RouteSeat.COL_ID, skuList.stream().map(RouteSku::getSeatId).collect(Collectors.toList())).eq(RouteSeat.COL_DELETED, false));
            seatList.forEach(routeSeat -> routeSeat.setUsed(false));
            routeSeatService.updateBatchById(seatList);
        }
        if (orderInfo.getRouteType().equals(RouteTypeEnum.All_SEATS.getCode())) {
            //恢复包船sku库存
            OrderInfoDetail orderInfoDetail = orderInfoDetailService.getOne(new QueryWrapper<OrderInfoDetail>().eq(OrderInfoDetail.COL_ORDER_ID, orderId).eq(OrderInfoDetail.COL_DELETED, false));
            RouteSku sku = routeSkuService.getOne(new QueryWrapper<RouteSku>().eq(RouteSku.COL_ID, orderInfoDetail.getSkuId()));
            List<RouteSku> skuList = routeSkuService.list(new QueryWrapper<RouteSku>().eq(RouteSku.COL_ROUTE_SPU_ID, sku.getRouteSpuId()));
            skuList.forEach(routeSku -> routeSku.setStock(routeSku.getStock()+1));
            routeSkuService.updateBatchById(skuList);
        }
    }

    // /**
    //  * 生成订单快照
    //  */
    // private void generateSnapshot(OrderInfo orderInfo) {
    //     CompletableFuture.runAsync(()->{
    //         OrderSnapshot orderSnapshot = new OrderSnapshot();
    //         RouteSpu route = routeSpuService.getById(orderInfo.getRouteId());
    //         orderSnapshot.setOrderId(orderInfo.getId());
    //         orderSnapshot.setShipId(route.getShipId());
    //         orderSnapshot.setDestination(route.getDestination());
    //         orderSnapshot.setRouteType(route.getRouteType());
    //         orderSnapshot.setSeats(route.getSeats());
    //         orderSnapshot.setPeopleCount(orderInfo.getPeopleCount());
    //         orderSnapshot.setStartTime(route.getStartTime());
    //         orderSnapshot.setEndTime(route.getEndTime());
    //         orderSnapshot.setTotalPrice(orderInfo.getAmount());
    //         orderSnapshot.setFinalStatus(orderInfo.getStatus());
    //         orderSnapshotMapper.insert(orderSnapshot);
    //     });
    // }

}
